#pragma once

#include <iostream>
#include <string>
#include <cstdlib>
#include <cstring>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <pthread.h>
#include <signal.h>
#include <signal.h>
#include "Log.hpp"
#include "ThreadPool.hpp"
#include "Task.hpp"
#include "Daemon.hpp"


using namespace std;

const int defaultfd = -1;
const string defaultip = "0.0.0.0";
extern Log lg;
const int backlog = 10;     //积压

enum
{
    UsageError = 1,
    SocketError,
    BindError,
    ListenError,
};


class TcpServer
{
public:
    TcpServer(const uint16_t port, const string ip = defaultip)
        : _port(port)
        , _ip(ip)
        , _listensock(defaultfd)
    {}

    ~TcpServer()
    {
        if (_listensock!= defaultfd)
        {
            close(_listensock);
        }
    }

    void InitServer()
    {
        _listensock = socket(AF_INET, SOCK_STREAM, 0);
        if (_listensock == -1)
        {
            lg(Fatal, "create socket, errno: %d, errstring: %s", errno, strerror(errno));
            exit(SocketError);
        }
        lg(Info, "create socket success, listensock_: %d", _listensock);

        int opt = 1;
        setsockopt(_listensock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));     // 防止偶发性的服务器无法进行立即重启(tcp协议的时候再说)

        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));   //bzero(&local, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_addr.s_addr = inet_addr(_ip.c_str());
        local.sin_port = htons(_port);

        if (bind(_listensock, (struct sockaddr*)&local, sizeof(local)) == -1)
        {
            lg(Fatal, "bind error, errno: %d, errstring: %s", errno, strerror(errno));
            exit(BindError);
        }
        lg(Info, "bind socket success, listensock_: %d", _listensock);

        // Tcp是面向连接的，服务器一般是比较“被动的”，服务器一直处于一种，一直在等待连接到来的状态
        if (listen(_listensock, backlog) == -1)       //第二个参数用来设置最大积压
        {
            lg(Fatal, "listen error, errno: %d, errstring: %s", errno, strerror(errno));
            exit(ListenError);
        }
        lg(Info, "listen socket success, listensock_: %d", _listensock);
    }

    void Start()
    {
        Daemon();
        ThreadPool<Task>::GetInstance()->Start();
        lg(Info, "tcpServer is running....");

        for(;;)
        {
            //1.获取accsocket
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            int accsock = accept(_listensock, (struct sockaddr*)&peer, &len);
            if (accsock == -1)
            {
                lg(Warning, "accept error, errno: %d, errstring: %s", errno, strerror(errno)); //?
                continue;   //只是接受一次失败，继续接受下一个连接
            }

            uint16_t peerport = ntohs(peer.sin_port);
            char clientip[32];
            inet_ntop(AF_INET, &(peer.sin_addr), clientip, sizeof(clientip));

            // 2. 根据新连接来进行通信
            lg(Info, "get a new link..., sockfd: %d, client ip: %s, client port: %d", accsock, clientip, peerport);

            //线程池版本
            Task t(accsock, clientip, peerport);
            ThreadPool<Task>::GetInstance()->Push(t);
        }
        
    }


private:
    int _listensock;
    uint16_t _port;
    string _ip;
};